"""数据库管理器"""

# 抑制librosa的pkg_resources弃用警告
import warnings
warnings.filterwarnings('ignore', category=UserWarning, module='librosa')

import asyncio
from typing import Dict, Any, Optional, List
from loguru import logger

from .redis_client import RedisClient
from .mongodb_client import MongoDBClient
from .neo4j_client import Neo4jClient

# ChromaDB导入设为可选
try:
    from .chromadb_client import ChromaDBClient
    CHROMADB_AVAILABLE = True
except ImportError as e:
    logger.warning(f"ChromaDB不可用: {e}")
    ChromaDBClient = None
    CHROMADB_AVAILABLE = False


class DatabaseManager:
    """数据库管理器 - 统一管理所有数据库连接"""
    
    def __init__(self, config: Dict[str, Any]):
        self.config = config
        self.redis_client: Optional[RedisClient] = None
        self.mongodb_client: Optional[MongoDBClient] = None
        self.neo4j_client: Optional[Neo4jClient] = None
        # 使用私有属性作为 ChromaDB 客户端的后备存储，避免与只读 property 冲突
        self._chromadb_client: Optional[ChromaDBClient] = None
        self._initialized = False
    
    async def connect_all(self):
        """连接所有数据库 - initialize()方法的别名，保持向后兼容性"""
        await self.initialize()
    
    async def initialize(self):
        """初始化所有数据库连接"""
        if self._initialized:
            logger.warning("数据库管理器已经初始化")
            return
        
        logger.info("开始初始化数据库连接...")
        
        try:
            # 初始化Redis客户端
            redis_config = self.config.get('databases', {}).get('redis', {})
            redis_enabled = redis_config.get('enabled', True)  # 默认启用
            if redis_enabled:
                try:
                    self.redis_client = RedisClient(self.config)
                    await self.redis_client.connect()
                    logger.info("Redis连接初始化成功")
                except Exception as e:
                    logger.warning(f"Redis连接失败，使用 NoOp 适配器: {e}")
                    self.redis_client = _NoOpRedisClient(self.config)
            else:
                logger.info("Redis未启用，使用 NoOp 适配器")
                self.redis_client = _NoOpRedisClient(self.config)
            
            # 初始化MongoDB客户端
            mongodb_config = self.config.get('databases', {}).get('mongodb', {})
            mongodb_enabled = mongodb_config.get('enabled', True)  # 默认启用
            if mongodb_enabled:
                try:
                    self.mongodb_client = MongoDBClient(self.config)
                    await self.mongodb_client.connect()
                    logger.info("MongoDB连接初始化成功")
                except Exception as e:
                    logger.warning(f"MongoDB连接失败，使用 NoOp 适配器: {e}")
                    self.mongodb_client = _NoOpMongoClient(self.config)
            else:
                logger.info("MongoDB未启用，使用 NoOp 适配器")
                self.mongodb_client = _NoOpMongoClient(self.config)
            
            # 初始化Neo4j客户端
            neo4j_config = self.config.get('databases', {}).get('neo4j', {})
            neo4j_enabled = neo4j_config.get('enabled', False)  # 默认禁用
            if neo4j_enabled:
                try:
                    self.neo4j_client = Neo4jClient(self.config)
                    await self.neo4j_client.connect()
                    logger.info("Neo4j连接初始化成功")
                except Exception as e:
                    logger.warning(f"Neo4j连接失败，使用 NoOp 适配器: {e}")
                    self.neo4j_client = _NoOpNeo4jClient(self.config)
            else:
                logger.info("Neo4j未启用，使用 NoOp 适配器")
                self.neo4j_client = _NoOpNeo4jClient(self.config)
            
            # 初始化ChromaDB客户端
            chromadb_config = self.config.get('databases', {}).get('chromadb', {})
            chroma_enabled = chromadb_config.get('enabled', True)  # 默认启用
            if CHROMADB_AVAILABLE and chroma_enabled:
                # 通过 property 的 setter 进行赋值
                self.chromadb_client = ChromaDBClient(self.config)
                await self.chromadb_client.connect()
                logger.info("ChromaDB连接初始化成功")
            else:
                # 不可用或未启用时，使用 NoOp 适配器，保证上层调用不报错
                self.chromadb_client = _NoOpChromaClient(self.config)
                if not CHROMADB_AVAILABLE:
                    logger.info("ChromaDB不可用，使用 NoOp 适配器")
                else:
                    logger.info("ChromaDB未启用，使用 NoOp 适配器")
            
            self._initialized = True
            logger.info("所有数据库连接初始化完成")
            
        except Exception as e:
            logger.error(f"数据库初始化失败: {e}")
            await self.close()
            raise
    
    async def close(self):
        """关闭所有数据库连接"""
        logger.info("开始关闭数据库连接...")
        
        close_tasks = []
        
        if self.redis_client:
            close_tasks.append(self.redis_client.close())
        
        if self.mongodb_client:
            close_tasks.append(self.mongodb_client.close())
        
        if self.neo4j_client:
            close_tasks.append(self.neo4j_client.close())
        
        if self.chromadb_client:
            close_tasks.append(self.chromadb_client.close())
        
        if close_tasks:
            await asyncio.gather(*close_tasks, return_exceptions=True)
        
        self._initialized = False
        logger.info("所有数据库连接已关闭")
    
    async def close_all(self):
        """关闭所有数据库连接 - close()方法的别名，保持向后兼容性"""
        await self.close()
    
    async def health_check(self) -> Dict[str, bool]:
        """检查所有数据库连接健康状态"""
        health_status = {}
        
        if self.redis_client:
            try:
                health_status['redis'] = await self.redis_client.ping()
            except Exception as e:
                logger.error(f"Redis健康检查失败: {e}")
                health_status['redis'] = False
        
        if self.mongodb_client:
            try:
                health_status['mongodb'] = await self.mongodb_client.ping()
            except Exception as e:
                logger.error(f"MongoDB健康检查失败: {e}")
                health_status['mongodb'] = False
        
        if self.neo4j_client:
            try:
                health_status['neo4j'] = await self.neo4j_client.ping()
            except Exception as e:
                logger.error(f"Neo4j健康检查失败: {e}")
                health_status['neo4j'] = False
        
        if self.chromadb_client:
            try:
                health_status['chromadb'] = await self.chromadb_client.ping()
            except Exception as e:
                logger.error(f"ChromaDB健康检查失败: {e}")
                health_status['chromadb'] = False
        
        return health_status
    
    def get_redis(self) -> RedisClient:
        """获取Redis客户端"""
        if not self.redis_client:
            raise RuntimeError("Redis客户端未初始化")
        return self.redis_client
    
    def get_mongodb(self) -> MongoDBClient:
        """获取MongoDB客户端"""
        if not self.mongodb_client:
            raise RuntimeError("MongoDB客户端未初始化")
        return self.mongodb_client
    
    def get_neo4j(self) -> Neo4jClient:
        """获取Neo4j客户端"""
        if not self.neo4j_client:
            raise RuntimeError("Neo4j客户端未初始化")
        return self.neo4j_client
    
    def get_chromadb(self) -> 'ChromaDBClient':
        """获取ChromaDB客户端"""
        if not CHROMADB_AVAILABLE:
            raise RuntimeError("ChromaDB不可用，请安装: pip install chromadb")
        if not self.chromadb_client:
            raise RuntimeError("ChromaDB客户端未初始化")
        return self.chromadb_client
    
    @property
    def chromadb_client(self):
        return self._chromadb_client
    
    @chromadb_client.setter
    def chromadb_client(self, value):
        self._chromadb_client = value
    
    @property
    def is_initialized(self) -> bool:
        """检查是否已初始化"""
        return self._initialized
    
    async def __aenter__(self):
        """异步上下文管理器入口"""
        await self.initialize()
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        """异步上下文管理器退出"""
        await self.close()
    
    async def shutdown(self):
        """关闭数据库连接（别名方法）"""
        await self.close()


class _NoOpChromaClient:
    """ChromaDB 的 No-Op 适配器：在不可用或未启用时提供兼容接口，避免上层调用失败"""

    def __init__(self, config: Dict[str, Any]):
        self.config = config
    
    def __bool__(self):
        """支持真值测试，返回True表示对象存在"""
        return True

    async def connect(self):
        return None

    async def close(self):
        return None

    async def ping(self) -> bool:
        # 不可用状态返回 False，用于健康检查
        return False

    async def store_conversation(self, message_id: str, content: str, metadata: Dict[str, Any]) -> str:
        # 直接返回 message_id，表示“已忽略但不报错”
        return message_id

    async def search_conversations(self, query: str, user_id: Optional[str] = None, limit: int = 10):
        # 返回空结果，表示没有向量搜索能力
        return []

    async def delete_conversation(self, conversation_id: str) -> bool:
        # 返回 True，避免删除流程被阻塞
        return True

    # -------- 新增适配：文档相关 --------
    async def store_document(self, document_id: str, content: str, metadata: Dict[str, Any]) -> str:
        # 直接返回传入的 document_id
        return document_id

    async def delete_document(self, document_id: str) -> bool:
        # 无操作，返回 True
        return True

    async def get_document_stats(self) -> Dict[str, Any]:
        # 返回占位统计，确保调用方结构安全
        return {
            "documents": {"count": 0, "last_updated": None},
            "status": "noop"
        }

    # -------- 新增适配：记忆相关 --------
    async def store_memory(self, memory_id: str, content: str, metadata: Dict[str, Any]) -> str:
        # 直接返回传入的 memory_id
        return memory_id

    async def search_memories(self, query: str, user_id: Optional[str] = None, limit: int = 10):
        # 返回空列表
        return []

    async def delete_memory(self, memory_id: str) -> bool:
        # 无操作，返回 True
        return True

    async def get_stats(self) -> Dict[str, Any]:
        # 返回占位统计，确保调用方结构安全
        return {
            "connected": False,
            "collections": {
                "memories": {"count": 0},
                "documents": {"count": 0},
                "conversations": {"count": 0},
                "knowledge": {"count": 0}
            },
            "total_documents": 0,
            "status": "noop"
        }

    # -------- 新增适配：通用维护/统计 --------
    async def cleanup_old_vectors(self, cutoff_date) -> int:
        # 无清理动作，返回 0
        return 0

    async def get_stats(self) -> Dict[str, Any]:
        # 返回总体占位统计
        return {
            "memories": {"count": 0},
            "documents": {"count": 0},
            "conversations": {"count": 0},
            "knowledge": {"count": 0},
            "status": "noop"
        }

    async def get_document_stats(self) -> Dict[str, Any]:
        # 返回占位统计，确保调用方结构安全
        return {
            "documents": {"count": 0, "last_updated": None},
            "status": "noop"
        }


class _NoOpMongoClient:
    """MongoDB客户端的无操作实现，当MongoDB不可用或禁用时使用"""
    
    def __init__(self, config: Dict[str, Any]):
        self.config = config
        self.is_connected = False
    
    def __bool__(self):
        """支持真值测试，返回True表示对象存在"""
        return True
    
    async def connect(self):
        self.is_connected = True
        return True
    
    async def close(self):
        self.is_connected = False
        return True
    
    async def ping(self) -> bool:
        return True
    
    def get_collection(self, name: str):
        return None
    
    # 对话相关方法
    async def store_conversation(self, conversation_data: Dict[str, Any]) -> str:
        return "noop_conversation_id"
    
    async def get_conversation(self, conversation_id: str) -> Optional[Dict[str, Any]]:
        return None
    
    async def get_conversations_by_session(self, session_id: str, limit: int = 50) -> List[Dict[str, Any]]:
        return []
    
    async def get_conversations_by_user(self, user_id: str, limit: int = 100, skip: int = 0) -> List[Dict[str, Any]]:
        return []
    
    async def update_conversation(self, conversation_id: str, updates: Dict[str, Any]) -> bool:
        return True
    
    async def get_user_conversations(self, user_id: str, limit: int = 20, status: Optional[str] = None) -> List[Dict[str, Any]]:
        return []
    
    async def get_conversations_before_date(self, cutoff_date) -> List[Dict[str, Any]]:
        return []
    
    async def get_conversation_stats(self) -> Dict[str, Any]:
        return {"total": 0, "by_status": {}, "by_user": {}}
    
    async def delete_conversation(self, conversation_id: str) -> bool:
        return True
    
    # 记忆相关方法
    async def store_memory(self, memory_data: Dict[str, Any]) -> str:
        return "noop_memory_id"
    
    async def get_memories_by_user(self, user_id: str, memory_type: Optional[str] = None, limit: int = 50) -> List[Dict[str, Any]]:
        return []
    
    async def search_memories(self, user_id: str, query: str, memory_type: Optional[str] = None, limit: int = 20) -> List[Dict[str, Any]]:
        return []
    
    # 事件相关方法
    async def store_event(self, event_data: Dict[str, Any]) -> str:
        return "noop_event_id"
    
    async def get_events_by_user(self, user_id: str, event_type: Optional[str] = None, limit: int = 50, start_date=None, end_date=None) -> List[Dict[str, Any]]:
        return []
    
    # 知识节点相关方法
    async def store_knowledge_node(self, node_data: Dict[str, Any]) -> str:
        return "noop_node_id"
    
    async def get_knowledge_node(self, node_id: str) -> Optional[Dict[str, Any]]:
        return None
    
    # 文档相关方法
    async def store_document(self, document_data: Dict[str, Any]) -> str:
        return "noop_document_id"
    
    async def get_document(self, document_id: str) -> Optional[Dict[str, Any]]:
        return None
    
    async def update_document(self, document_id: str, updates: Dict[str, Any]) -> bool:
        return True
    
    async def delete_document(self, document_id: str) -> bool:
        return True
    
    async def get_user_documents(self, user_id: str, limit: int = 50, skip: int = 0, status: Optional[str] = None) -> List[Dict[str, Any]]:
        return []
    
    async def get_document_stats(self, user_id: Optional[str] = None) -> Dict[str, Any]:
        return {"total": 0, "by_status": {}, "by_user": {}}
    
    # 对话消息相关方法
    async def store_conversation_message(self, conversation_id: str, message_data: Dict[str, Any]) -> str:
        return "noop_message_id"
    
    async def get_conversation_messages(self, conversation_id: str, limit: Optional[int] = None, offset: int = 0) -> List[Dict[str, Any]]:
        return []
    
    # 统计和维护方法
    async def get_user_statistics(self, user_id: str) -> Dict[str, Any]:
        return {
            "conversations": 0,
            "memories": 0,
            "events": 0,
            "documents": 0
        }
    
    async def cleanup_old_data(self, days: int = 90):
        return 0
    
    async def get_stats(self) -> Dict[str, Any]:
        return {
            "database_size": 0,
            "storage_size": 0,
            "index_size": 0,
            "collections": {},
            "status": "noop"
        }


class _NoOpNeo4jClient:
    """Neo4j客户端的无操作实现，当Neo4j不可用或禁用时使用"""
    
    def __init__(self, config: Dict[str, Any]):
        self.config = config
        self.is_connected = False
    
    def __bool__(self):
        """支持真值测试，返回True表示对象存在"""
        return True
    
    async def connect(self):
        self.is_connected = True
        return True
    
    async def close(self):
        self.is_connected = False
        return True
    
    async def ping(self) -> bool:
        return True
    
    async def get_session(self):
        return None
    
    # 查询执行方法
    async def execute_query(self, query: str, parameters: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
        return []
    
    async def execute_read_query(self, query: str, parameters: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
        return []
    
    async def execute_write_query(self, query: str, parameters: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        return {"nodes_created": 0, "relationships_created": 0, "properties_set": 0}
    
    # 用户节点相关方法
    async def create_user_node(self, user_id: str, user_data: Dict[str, Any]) -> bool:
        return True
    
    async def get_user_node(self, user_id: str) -> Optional[Dict[str, Any]]:
        return None
    
    # 概念节点相关方法
    async def create_concept_node(self, concept_id: str, concept_data: Dict[str, Any]) -> bool:
        return True
    
    async def find_concepts_by_name(self, name: str, limit: int = 10) -> List[Dict[str, Any]]:
        return []
    
    # 记忆节点相关方法
    async def create_memory_node(self, memory_id: str, memory_data: Dict[str, Any]) -> bool:
        return True
    
    # 关系相关方法
    async def create_relationship(self, from_node_id: str, from_node_type: str, to_node_id: str, to_node_type: str, relationship_type: str, properties: Optional[Dict[str, Any]] = None) -> bool:
        return True
    
    async def get_relationships(self, node_id: str, node_type: str, relationship_type: Optional[str] = None, direction: str = "both", limit: int = 50) -> List[Dict[str, Any]]:
        return []
    
    # 路径查找方法
    async def find_shortest_path(self, from_node_id: str, from_node_type: str, to_node_id: str, to_node_type: str, max_depth: int = 5) -> Optional[Dict[str, Any]]:
        return None
    
    async def find_related_concepts(self, concept_id: str, depth: int = 2, limit: int = 20) -> List[Dict[str, Any]]:
        return []
    
    # 统计和分析方法
    async def get_node_degree(self, node_id: str, node_type: str) -> Dict[str, int]:
        return {"in_degree": 0, "out_degree": 0, "total_degree": 0}
    
    async def get_graph_statistics(self) -> Dict[str, Any]:
        return {
            "nodes": {"total": 0, "by_type": {}},
            "relationships": {"total": 0, "by_type": {}},
            "status": "noop"
        }
    
    # 维护方法
    async def cleanup_orphaned_nodes(self) -> int:
        return 0
    
    async def delete_old_memories(self, days: int = 365) -> int:
        return 0
    
    # 统计方法
    async def get_stats(self) -> Dict[str, Any]:
        return {
            "nodes": {"total": 0, "by_type": {}},
            "relationships": {"total": 0, "by_type": {}},
            "status": "noop"
        }
    
    async def find_related_memories(self, query: str, user_id: str, limit: int = 10) -> List[Dict[str, Any]]:
        return []
    
    async def find_related_knowledge(self, query: str, user_id: str, limit: int = 10) -> List[Dict[str, Any]]:
        return []
    
    async def find_related_documents(self, document_id: str, limit: int = 5) -> List[Dict[str, Any]]:
        return []
    
    async def get_user_graph_stats(self, user_id: str) -> Dict[str, Any]:
        return {'memories': 0, 'documents': 0, 'concepts': 0}
    
    async def get_knowledge_stats(self) -> Dict[str, Any]:
        return {
            "concepts": 0,
            "relationships": 0,
            "users": 0,
            "status": "noop"
        }
    
    async def get_user_knowledge_stats(self, user_id: str) -> Dict[str, Any]:
        return {
            "user_id": user_id,
            "concepts": 0,
            "relationships": 0,
            "memories": 0,
            "status": "noop"
        }


class _NoOpRedisClient:
    """Redis NoOp 适配器，当Redis不可用时使用"""
    
    def __init__(self, config: Dict[str, Any]):
        self.config = config
    
    def __bool__(self):
        return False
    
    async def connect(self):
        pass
    
    async def close(self):
        pass
    
    async def ping(self) -> bool:
        return False
    
    async def set(self, key: str, value: str, ex: Optional[int] = None) -> bool:
        return True
    
    async def get(self, key: str) -> Optional[str]:
        return None
    
    async def delete(self, key: str) -> bool:
        return True
    
    async def exists(self, key: str) -> bool:
        return False
    
    async def expire(self, key: str, seconds: int) -> bool:
        return True
    
    async def set_hash(self, key: str, value: Any, expire: Optional[int] = None) -> bool:
        return True
    
    async def get_hash(self, key: str, field: str) -> Optional[str]:
        return None
    
    async def get_all_hash(self, key: str) -> Dict[str, str]:
        return {}
    
    async def delete_hash(self, key: str, field: str) -> bool:
        return True
    
    async def increment(self, key: str, amount: int = 1) -> int:
        return amount
    
    async def set_list(self, key: str, values: List[str]) -> bool:
        return True
    
    async def get_list(self, key: str) -> List[str]:
        return []
    
    async def push_to_list(self, key: str, value: str) -> bool:
        return True
    
    async def pop_from_list(self, key: str) -> Optional[str]:
        return None
    
    async def get_keys(self, pattern: str = "*") -> List[str]:
        return []
    
    async def get_keys_pattern(self, pattern: str) -> List[str]:
        return []
    
    async def flush_db(self) -> bool:
        return True